<template>
<div>
  <div :class="$style.podium" v-if="podiumVisible">
    <div v-for="i in [2, 4, 5, 3, 1]">
      <div v-for="patron in patrons[i - 1]" :key="patron.from"
        :class="[$style.rating, $style[`rating-${patron.style}`]]"
        >{{ patron.from }}{{ (patron.months > 1) ? ` x${patron.months}` : null }}</div>
    </div>
  </div>
  <div :class="[$style.patronsHorizontal, { 'invisible': podiumVisible }]" :onMouseenter="showPodium">
    <div class="bg-gray-800 rounded p-1 justify-center text-center w-44 shrink-0 flex items-center">
      {{ t('settings.thank_you') }}
    </div>
    <div class="overflow-x-hidden whitespace-nowrap p-1 text-base">
      <span :class="$style.patronsLine">{{ patronsString[0] }}</span><br>
      <span :class="$style.patronsLine">{{ patronsString[1] }}</span>
    </div>
  </div>
  <div :class="$style.window" class="grow layout-column" :onMouseenter="hidePodium">
    <AppTitleBar @close="cancel" :title="t('settings.title')" />
    <div class="flex grow min-h-0">
      <div class="pl-2 pt-2 bg-gray-900 flex flex-col gap-1" style="min-width: 10rem;">
        <template v-for="item of menuItems">
          <button v-if="item.type === 'menu-item'"
            @click="item.select" :class="[$style['menu-item'], { [$style['active']]: item.isSelected }]">{{ item.name }}</button>
          <div v-else
            class="border-b mx-2 border-gray-800" />
        </template>
        <button v-if="menuItems.length >= 4"
          :class="$style['quit-btn']" @click="quit">{{ t('app.quit') }}</button>
        <div class="text-gray-400 text-center mt-auto pr-3 pt-4 pb-12" style="max-width: fit-content; min-width: 100%;">
          <img class="mx-auto mb-1" src="/images/peepoLove2x.webp">
          {{ t('Support development on') }}<br> <a href="https://patreon.com/awakened_poe_trade" class="inline-flex mt-1" target="_blank"><img class="inline h-5" src="/images/Patreon.svg"></a>
        </div>
      </div>
      <div class="text-gray-100 grow layout-column bg-gray-900">
        <div class="grow overflow-y-auto bg-gray-800 rounded-tl">
          <component v-if="configClone"
            :is="selectedComponent" :config="configClone" :configWidget="configWidget" />
        </div>
        <div class="border-t bg-gray-900 border-gray-600 p-2 flex justify-end gap-x-2">
          <button @click="save" class="px-3 bg-gray-800 rounded">{{ t('Save') }}</button>
          <button @click="cancel" class="px-3">{{ t('Cancel') }}</button>
        </div>
      </div>
    </div>
  </div>
</div>
</template>

<script lang="ts">
import { defineComponent, shallowRef, computed, Component, PropType, nextTick, inject, reactive, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { AppConfig, updateConfig, saveConfig, pushHostConfig, Config } from '@/web/Config'
import { APP_PATRONS } from '@/assets/data'
import { Host } from '@/web/background/IPC'
import type { Widget, WidgetManager, WidgetSpec } from '@/web/overlay/interfaces'
import AppTitleBar from '@/web/ui/AppTitlebar.vue'
import SettingsHotkeys from './hotkeys.vue'
import SettingsChat from './chat.vue'
import SettingsGeneral from './general.vue'
import SettingsAbout from './about.vue'
import SettingsPricecheck from '../price-check/settings-price-check.vue'
import SettingsItemcheck from '../item-check/settings-item-check.vue'
import SettingsDebug from './debug.vue'
import SettingsMaps from '../map-check/settings-maps.vue'
import SettingsStashSearch from '../stash-search/stash-search-editor.vue'
import SettingsStopwatch from '../stopwatch/settings-stopwatch.vue'
import SettingsItemSearch from '../item-search/settings-item-search.vue'

function shuffle<T> (array: T[]): T[] {
  let currentIndex = array.length
  while (currentIndex !== 0) {
    const randomIndex = Math.floor(Math.random() * currentIndex)
    currentIndex--;
    [array[currentIndex], array[randomIndex]] =
      [array[randomIndex], array[currentIndex]]
  }
  return array
}

function quit () {
  Host.sendEvent({
    name: 'CLIENT->MAIN::user-action',
    payload: { action: 'quit' }
  })
}

export default defineComponent({
  widget: {
    type: 'settings',
    instances: 'single',
    initInstance: () => {
      return {
        wmId: 0,
        wmType: 'settings',
        wmTitle: '{icon=fa-cog}',
        wmWants: 'hide',
        wmZorder: 'exclusive',
        wmFlags: ['invisible-on-blur', 'ignore-ui-visibility']
      }
    }
  } satisfies WidgetSpec,
  components: { AppTitleBar },
  props: {
    config: {
      type: Object as PropType<Widget>,
      required: true
    }
  },
  setup (props) {
    const wm = inject<WidgetManager>('wm')!
    const { t } = useI18n()

    nextTick(() => {
      props.config.wmWants = 'hide'
    })

    const selectedComponent = shallowRef<Component>(SettingsHotkeys)

    const podiumVisible = shallowRef(false)
    const patrons = shallowRef<Array<typeof APP_PATRONS>>([])

    const configClone = shallowRef<Config | null>(null)
    watch(() => props.config.wmWants, (wmWants) => {
      if (wmWants === 'show') {
        configClone.value = reactive(JSON.parse(JSON.stringify(AppConfig())))
        patrons.value = [1, 2, 3, 4, 5].map(i =>
          shuffle(APP_PATRONS.filter(row => row.style === i))
        )
      } else {
        configClone.value = null
        if (selectedWmId.value != null) {
          selectedWmId.value = null
          selectedComponent.value = SettingsHotkeys
        }
        podiumVisible.value = false
      }
    })

    const selectedWmId = shallowRef<number | null>(null)
    const configWidget = computed(() => configClone.value?.widgets.find(w => w.wmId === selectedWmId.value))

    watch(() => props.config.wmFlags, (wmFlags) => {
      const flagStr = wmFlags.find(flag => flag.startsWith('settings::widget='))
      if (flagStr) {
        const _wmId = Number(flagStr.split('=')[1])
        const _widget = wm.widgets.value.find(w => w.wmId === _wmId)!
        selectedWmId.value = _wmId
        selectedComponent.value = menuByType(_widget.wmType)[0][0]
        wm.setFlag(props.config.wmId, flagStr, false)
      }
    }, { deep: true })

    const menuItems = computed(() => flatJoin(
      menuByType(configWidget.value?.wmType)
        .map(group => group.map(component => ({
          name: t(component.name!),
          select () { selectedComponent.value = component },
          isSelected: (selectedComponent.value === component),
          type: 'menu-item' as const
        }))),
      () => ({ type: 'separator' as const })
    ))

    return {
      t,
      save () {
        updateConfig(configClone.value!)
        saveConfig()
        pushHostConfig()

        wm.hide(props.config.wmId)
      },
      cancel () {
        wm.hide(props.config.wmId)
      },
      quit,
      menuItems,
      selectedComponent,
      configClone,
      configWidget,
      patrons,
      patronsString: computed(() => {
        return [true, false].map(firstHalf => {
          return patrons.value.flatMap(tier => {
            const half = Math.ceil(tier.length / 2)
            tier = (firstHalf) ? tier.slice(0, half) : tier.slice(half)
            return tier.map(e => e.from)
          }).reverse().join(' • ')
        })
      }),
      podiumVisible,
      showPodium () { podiumVisible.value = true },
      hidePodium () { podiumVisible.value = false }
    }
  }
})

function menuByType (type?: string) {
  switch (type) {
    case 'stash-search':
      return [[SettingsStashSearch]]
    case 'timer':
      return [[SettingsStopwatch]]
    case 'item-check':
      return [[SettingsItemcheck, SettingsMaps]]
    case 'price-check':
      return [[SettingsPricecheck]]
    case 'item-search':
      return [[SettingsItemSearch]]
    default:
      return [
        [SettingsHotkeys, SettingsChat],
        [SettingsGeneral],
        [SettingsPricecheck, SettingsMaps, SettingsItemcheck],
        [SettingsDebug, SettingsAbout]
      ]
  }
}

function flatJoin<T, J> (arr: T[][], joinEl: () => J) {
  const out: Array<T | J> = []
  for (const nested of arr) {
    out.push(...nested)
    out.push(joinEl())
  }
  return out.slice(0, -1)
}
</script>

<style lang="postcss" module>
.window {
  position: absolute;
  top: 0; bottom: 0; left: 0; right: 0;
  margin: 0 auto;
  max-width: 50rem;
  max-height: 38rem;
  overflow: hidden;
  @apply bg-gray-800;
  @apply rounded-b;
  &:global {
    animation-name: slideInDown;
    animation-duration: 1s;
  }
}

.menu-item {
  text-align: left;
  @apply p-2;
  line-height: 1;
  @apply text-gray-600;
  @apply rounded-l;

  &:hover {
    @apply text-gray-100;
  }

  &.active {
    @apply text-gray-400;
    @apply bg-gray-800;
  }
}

.quit-btn {
  @apply text-gray-600;
  @apply border border-gray-800;
  @apply p-1 mt-2 mr-2 rounded;

  &:hover {
    @apply text-red-400;
    @apply border-red-400;
  }
}

.patronsHorizontal {
  @apply bg-gray-900 p-1 rounded gap-1;
  position: absolute;
  top: 40rem; left: 0; right: 0;
  margin: 0 auto;
  max-width: 50rem;
  display: flex;
  &:global {
    animation-name: slideInDown;
    animation-duration: 1s;
  }
}

@keyframes slide {
  0% { transform: translate(0%, 0); }
  4% { transform: translate(0%, 0); }
  100% { transform: translate(-99%, 0); }
}
.patronsLine {
  display: inline-block;
  animation: slide 64s linear infinite;
}

.podium {
  display: flex;
  position: absolute;
  top: auto;
  bottom: max(0px, calc((100% - 38rem) / 2 - 10rem));
  align-items: flex-end;
  width: 100%;
  justify-content: center;
  @apply gap-4 p-4;
  &:global {
    animation-name: fadeIn;
    animation-duration: 1.5s;
  }
}
.podium > div {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  min-width: min-content;
}
.podium > div:nth-child(1) { max-width: 18rem; }
.podium > div:nth-child(2) { max-width: 16rem; }
.podium > div:nth-child(3) { flex-direction: column; align-items: center; }
.podium > div:nth-child(4) { max-width: 24rem; }
.podium > div:nth-child(5) { max-width: 18rem; }

.rating {
  min-width: 3rem;
  text-align: center;
  white-space: nowrap;
  @apply px-1 border;
}
.rating-1 {
  background-color: rgb(0, 0, 0);
  color: rgb(190, 178, 135);
  border-color: currentColor;
  @apply text-base;
}
.rating-2 {
  background-color: rgb(210, 178, 135);
  color: rgb(0, 0, 0);
  border-color: currentColor;
  @apply text-lg;
}
.rating-3 {
  background-color: rgb(213, 159, 0);
  color: rgb(0, 0, 0);
  border-color: currentColor;
  @apply text-lg;
}
.rating-4 {
  background-color: rgb(240, 90, 35);
  color: rgb(255, 255, 255);
  border-color: currentColor;
  @apply text-xl;
}
.rating-5 {
  background-color: rgb(255, 255, 255);
  color: rgb(255, 0, 0);
  border-color: currentColor;
  @apply text-2xl;
}
</style>
